import sys
from PyQt5.QtWidgets import QApplication, QMainWindow,  QWidget, QLabel, QLineEdit, QVBoxLayout, QHBoxLayout, QSpinBox, QGridLayout, QPushButton
import re
import statistics
import math

class EmissionMonitorCalculator(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("比对监测计算器")
        self.setGeometry(500, 200,400, 400)  # Increased window size
        self.parameters_info = {
            '颗粒物': {
                'precision': [1, 2, 2],
                'ranges': [
                    (lambda x: x > 200, "相对误差不超过±15%"),
                    (lambda x: x > 100, "相对误差不超过±20%"),
                    (lambda x: x > 50, "相对误差不超过±25%"),
                    (lambda x: x > 20, "相对误差不超过±30%"),
                    (lambda x: x > 10, "绝对误差不超过±6mg/m³"),
                    (lambda x: x <= 10, "绝对误差不超过±5mg/m³")
                ]
            },
            '二氧化硫': {
                'precision': [1, 2, 2],
                'ranges': [
                    (lambda x: x >= 715, "相对准确度≤15%"),
                    (lambda x: x >= 143, "绝对误差不超过±57mg/m³"),
                    (lambda x: x >= 57, "相对误差不超过±30%"),
                    (lambda x: x < 57, "绝对误差不超过±17mg/m³")
                ]
            },
            '氮氧化物': {
                'precision': [1, 2, 2],
                'ranges': [
                    (lambda x: x >= 513, "相对准确度≤15%"),
                    (lambda x: x >= 103, "绝对误差不超过±41mg/m³"),
                    (lambda x: x >= 41, "相对误差不超过±30%"),
                    (lambda x: x < 41, "绝对误差不超过±12mg/m³")
                ]
            },
            '非甲烷总烃': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x >= 500, "相对准确度≤35%"),
                    (lambda x: x >= 50, "相对准确度≤40%"),
                    (lambda x: x < 50, "绝对误差的绝对值≤20mg/m³")
                ]
            },
            '流速': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x > 10, "相对误差不超过±10%"),
                    (lambda x: x <= 10, "相对误差不超过±12%")
                ]
            },
            '温度': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x >= 0.0, "绝对误差不超过±3℃")
                ]
            },
            '湿度': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x > 5.0, "相对误差不超过±25%"),
                    (lambda x: x <= 5.0, "绝对误差不超过±1.5%")
                ]
            },
            '含氧量': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x > 5.0, "相对准确度≤15%"),
                    (lambda x: x <= 5.0, "绝对误差不超过±1.0%")
                ]
            },
            '化学需氧量（废水）': {
                'precision': [0, 3, 3],
                'ranges': [
                    (lambda x: x >= 100, "相对误差不超过±15%"),
                    (lambda x: x >= 60, "相对误差不超过±20%"),
                    (lambda x: x >= 30, "相对误差不超过±30%"),
                    (lambda x: x < 30, "绝对误差不超过±5mg/L")
                ]
            },
            '流量(废水)': {
                'precision': [3, 3, 2],
                'ranges': [
                    (lambda x: x > 0, "相对误差不超过±10%")
                ]
            },
            '标准样品（废水)': {
                'precision': [0, 3, 2],
                'ranges': [
                    (lambda x: x > 0, "相对误差不超过±10%")
                ]
            },
            '总氮（废水）': {
                'precision': [2, 3, 2],
                'ranges': [
                    (lambda x: x >= 2, "相对误差不超过±15%"),
                    (lambda x: x < 2, "绝对误差不超过±0.3mg/L")
                ]
            },
            'pH(废水)': {
                'precision': [2, 3, 3],
                'ranges': [
                    (lambda x: x > 0, "绝对误差不超过±0.5")
                ]
            },
            '氨氮（废水）': {
                'precision': [2, 3, 3],
                'ranges': [
                    (lambda x: x >= 2, "相对误差不超过±15%"),
                    (lambda x: x < 2, "绝对误差不超过±0.3mg/L")
                ]
            },
            '总磷（废水）': {
                'precision': [2, 3, 3],
                'ranges': [
                    (lambda x: x >= 0.4, "相对误差不超过±15%"),
                    (lambda x: x < 0.4, "绝对误差不超过±0.04mg/L")
                ]
            },
            '高锰酸盐指数(地表水)': {
                'precision': [1, 3, 2],
                'ranges': [
                    (lambda x: x > 10, "相对误差不超过±20%"),
                    (lambda x: x > 4, "相对误差不超过±30%"),
                    (lambda x: x > 0.5, "相对误差不超过±40%")
                ]
            },
            'pH(地表水)': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x > 0, "绝对误差不超过±0.1")
                ]
            },
            '氨氮_地表水': {
                'precision': [3, 3, 2],
                'ranges': [
                    (lambda x: x > 1.5, "相对误差不超过±20%"),
                    (lambda x: x > 0.5, "相对误差不超过±30%"),
                    (lambda x: x > 0.01, "相对误差不超过±40%")
                ]
            },
            '总磷(地表水)': {
                'precision': [2, 2, 2],
                'ranges': [
                    (lambda x: x > 0.3, "相对误差不超过±20%"),
                    (lambda x: x > 0.1, "相对误差不超过±30%"),
                    (lambda x: x > 0.01, "相对误差不超过±40%")
                ]
            },
            '溶解氧(地表水)': {
                'precision': [1, 2, 2],
                'ranges': [
                    (lambda x: x > 0, "绝对误差不超过±0.3mg/L")
                ]
            },
        }

        self.selected_parameter = '颗粒物'
        self.reference_entries = [QLineEdit(self) for _ in range(9)]
        self.cems_entries = [QLineEdit(self) for _ in range(9)]
        self.reference_precision = QSpinBox(self)
        self.cems_precision = QSpinBox(self)
        self.accuracy_precision = QSpinBox(self)
        self.error_label = QLabel(self)
        self.result_label = QLabel(self)

        self.buttons = {}
        self.create_widgets()
        self.set_default_precisions()
        self.update_results()

    def set_default_precisions(self):
        default_values = self.parameters_info[self.selected_parameter]['precision']
        self.reference_precision.setValue(default_values[0])
        self.cems_precision.setValue(default_values[1])
        self.accuracy_precision.setValue(default_values[2])

    def create_widgets(self):
        main_layout = QVBoxLayout()

        button_grid_layout = QGridLayout()
        row = 0
        col = 0
        for idx, parameter in enumerate(self.parameters_info.keys()):
            button = QPushButton(parameter)
            button.clicked.connect(lambda checked, param=parameter: self.on_button_click(param))
            button_grid_layout.addWidget(button, row, col)
            self.buttons[parameter] = button
            col += 1
            if col >= 4:  # Adjust the number of columns as needed
                col = 0
                row += 1

        clear_layout = QHBoxLayout()
        clear_button = QPushButton("清空数据")
        clear_button.clicked.connect(self.clear_data)
        clear_layout.addStretch()
        clear_layout.addWidget(clear_button)

        grid_layout = QGridLayout()
        reference_label = QLabel("参比数据")
        grid_layout.addWidget(reference_label, 0, 1)
        for i, entry in enumerate(self.reference_entries):
            grid_layout.addWidget(QLabel(f"数据{i + 1}"), i + 1, 0)
            grid_layout.addWidget(entry, i + 1, 1)
            entry.textChanged.connect(self.update_results)
        cems_label = QLabel("在线数据")
        grid_layout.addWidget(cems_label, 0, 2)
        for i, entry in enumerate(self.cems_entries):
            grid_layout.addWidget(entry, i + 1, 2)
            entry.textChanged.connect(self.update_results)

        precision_layout = QHBoxLayout()
        precision_layout.addWidget(QLabel("参比平均保留位数:"))
        precision_layout.addWidget(self.reference_precision)
        precision_layout.addWidget(QLabel("在线平均保留位数:"))
        precision_layout.addWidget(self.cems_precision)
        precision_layout.addWidget(QLabel("正确度保留位数:"))
        precision_layout.addWidget(self.accuracy_precision)
        self.reference_precision.valueChanged.connect(self.update_results)
        self.cems_precision.valueChanged.connect(self.update_results)
        self.accuracy_precision.valueChanged.connect(self.update_results)

        self.error_label.setWordWrap(True)
        self.error_label.setStyleSheet(
            "background-color: thistle; border: 1px solid black; padding: 10px; font-size: 16px;"
        )
        self.result_label.setStyleSheet(
            "background-color: white; border: 1px solid black; padding: 10px; font-size: 18px;"
        )

        main_layout.addLayout(button_grid_layout)
        main_layout.addLayout(clear_layout)
        main_layout.addLayout(grid_layout)
        main_layout.addLayout(precision_layout)
        main_layout.addWidget(self.result_label)
        main_layout.addWidget(self.error_label)

        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)

    def on_button_click(self, parameter):
        self.selected_parameter = parameter
        self.set_default_precisions()
        self.update_results()
        for btn_param, button in self.buttons.items():
            if btn_param == parameter:
                button.setStyleSheet("background-color: lightblue;")  # Highlight the clicked button
            else:
                button.setStyleSheet("")  # Reset other buttons

    def round_half_even(self, value, places):
        multiplier = 10 ** places
        abs_value = abs(value) * multiplier
        fractional_part = abs_value % 1
        if fractional_part == 0.5:
            if int(abs_value) % 2 == 0:
                rounded_value = int(abs_value) / multiplier
            else:
                rounded_value = (int(abs_value) + 1) / multiplier
        else:
            rounded_value = round(abs_value) / multiplier
        return -rounded_value if value < 0 else rounded_value

    def validate_input(self, entry):
        try:
            float(entry)
            return True
        except ValueError:
            return False

    def RA(self, ref, cems, precision):
        n = len(ref)
        t_values = {
            5: 2.571, 6: 2.447, 7: 2.365, 8: 2.306, 9: 2.262, 10: 2.228, 11: 2.201,
            12: 2.179, 13: 2.16, 14: 2.145, 15: 2.131, 16: 2.12, 17: 2.11, 18: 2.101,
            19: 2.093, 20: 2.086, 21: 2.08, 22: 2.074, 23: 2.069, 24: 2.064, 25: 2.06,
            26: 2.056, 27: 2.052, 28: 2.048, 29: 2.045, 30: 2.042, 31: 2.04, 32: 2.037,
            33: 2.035, 34: 2.032, 35: 2.03, 36: 2.028, 37: 2.026, 38: 2.024, 39: 2.023,
            40: 2.021
        }
        if n >= 6:
            ref_avg = sum(ref) / len(ref) if ref else 0
            diff = [c - r for c, r in zip(cems, ref)]
            mean_diff = sum(diff) / n
            Sd = statistics.stdev(diff) if n > 1 else 0
            t_value = t_values.get(n - 1)
            cc = t_value * (Sd / math.sqrt(n)) if n > 0 else 0
            r_accuracy = ((abs(mean_diff) + abs(cc)) / ref_avg) * 100 if ref_avg != 0 else 0
            r_a_r = self.round_half_even(r_accuracy, precision)
            return r_a_r
        return 0

    def process_and_display_results(self, reference_values, cems_values, reference_precision, cems_precision,accuracy_precision):
        avg_ref = statistics.mean(reference_values)
        avg_cems = statistics.mean(cems_values)

        avg_ref_rounded = self.round_half_even(avg_ref, reference_precision)
        avg_cems_rounded = self.round_half_even(avg_cems, cems_precision)

        absolute_error = round(avg_cems_rounded - avg_ref_rounded,10)
        absolute_error_rounded = self.round_half_even(absolute_error, accuracy_precision)

        relative_error = (absolute_error / avg_ref_rounded * 100) if avg_ref_rounded != 0 else 0
        relative_error_rounded = self.round_half_even(relative_error, accuracy_precision)

        relative_accuracy_rounded = self.RA(reference_values, cems_values, accuracy_precision)

        result_text = (
            f"<span style='font-family: KaiTi;'>参比方法平均值:</span> <span style='font-family: Times New Roman;'>{avg_ref_rounded:.{reference_precision}f}</span><br>"
            f"<span style='font-family: KaiTi;'>CEMS平均值:</span> <span style='font-family: Times New Roman;'>{avg_cems_rounded:.{cems_precision}f}</span>"
        )
        self.result_label.setText(result_text)

        for condition, limit in self.parameters_info[self.selected_parameter]['ranges']:
            if condition(avg_ref_rounded):
                threshold = float(re.search(r'\d*\.?\d+', limit).group())
                error_type = re.search(r'(绝对误差的绝对值|相对准确度|相对误差|绝对误差)', limit).group()
                use_abs = "绝对误差的绝对值" in limit

                error_value = (
                    abs(absolute_error_rounded) if use_abs else
                    relative_error_rounded if "相对误差" in error_type else
                    relative_accuracy_rounded if "相对准确度" in error_type else
                    absolute_error_rounded
                )

                unit = re.search(r'(mg/m³|℃|%|mg/L)', limit)
                unit_str = unit.group(1) if unit else ''

                value_str = f"<span style='font-family: KaiTi;'>{error_value:.{accuracy_precision}f}{unit_str}</span>"

                if abs(error_value) > threshold:
                    self.error_label.setText(
                        f"<span style='font-family: KaiTi;'>计算结果({error_type}): </span>{value_str}<br><span style='font-family: KaiTi;'>限值要求：{limit}</span><br><span style='font-family: KaiTi;'>超标提示：比对结果超过标准限值 </span>"
                    )
                else:
                    self.error_label.setText(
                        f"<span style='font-family: KaiTi;'>计算结果({error_type}): </span>{value_str}<br><span style='font-family: KaiTi;'>限值要求：{limit}</span>"
                    )
                break

    def update_results(self):
        try:
            reference_values = [float(ref_entry.text()) for ref_entry in self.reference_entries if self.validate_input(ref_entry.text())]
            cems_values = [float(cems_entry.text()) for cems_entry in self.cems_entries if self.validate_input(cems_entry.text())]
            reference_precision = self.reference_precision.value()
            cems_precision = self.cems_precision.value()
            accuracy_precision = self.accuracy_precision.value()
            if not reference_values or not cems_values:
                raise ValueError("请至少输入一组有效数据")
            self.process_and_display_results(reference_values, cems_values, reference_precision, cems_precision, accuracy_precision)
        except ValueError as e:
            self.error_label.setText(f"<span style='font-family: KaiTi;'>{str(e)}</span>")
            self.result_label.clear()

    def clear_data(self):
        for entry in self.reference_entries + self.cems_entries:
            entry.clear()
        self.result_label.clear()
        self.error_label.clear()
#运行程序
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = EmissionMonitorCalculator()
    window.show()
    sys.exit(app.exec_())
